package com.zhu.rtda.heap.constant;

import com.zhu.classfile.constant.ConstantInfo;
import com.zhu.classfile.constant.ConstantPool;
import com.zhu.classfile.constant.ConstantTag;
import com.zhu.classfile.constant.base.*;
import com.zhu.rtda.heap.InstanceKlass;

/**
 * 运行时常量池（对应 Go 的 ConstantPool）
 *
 * 存储类或接口的常量数据，包括：
 * - 字面量（int, float, long, double, String）
 * - 符号引用（类、字段、方法、接口方法）
 */
public class RuntimeConstantPool {

    private InstanceKlass instanceKlass;
    private Constant[] consts;

    // region 构造与工厂方法

    private RuntimeConstantPool(InstanceKlass instanceKlass,Constant[] consts) {
        this.instanceKlass = instanceKlass;
        this.consts=consts;
    }

    /**
     * 工厂方法：根据 class 文件的常量池创建运行时常量池
     *
     * @param instanceKlass 当前类
     * @param cfConstantPool class 文件中的常量池
     * @return 运行时常量池
     */
    public static RuntimeConstantPool creteRuntimeConstantPool(InstanceKlass instanceKlass, ConstantPool cfConstantPool) {
        int cpCount = cfConstantPool.getSize();
        Constant[] consts = new Constant[cpCount];
        RuntimeConstantPool runtimeConstantPool = new RuntimeConstantPool(instanceKlass,consts);
        for (int i = 1; i < cpCount; i++) {
            ConstantInfo cpInfo = cfConstantPool.get(i);
            ConstantTag tag = ConstantTag.fromTag(cpInfo.getTag().getTagVal()); // 使用枚举解析
            Constant constant = null;

            switch (tag) {
                case CONSTANT_Integer:
                    ConstantIntegerInfo intInfo = (ConstantIntegerInfo) cpInfo;
                    constant =new IntegerConstant(intInfo.getValue()); // Integer
                    break;

                case CONSTANT_Float:
                    ConstantFloatInfo floatInfo = (ConstantFloatInfo) cpInfo;
                    constant = new FloatConstant(floatInfo.getValue()); // Float
                    break;

                case CONSTANT_Long:
                    ConstantLongInfo longInfo = (ConstantLongInfo) cpInfo;
                    constant = new LongConstant(longInfo.getValue()); // Long
                    i++; // 占两个 slot
                    break;

                case CONSTANT_Double:
                    ConstantDoubleInfo doubleInfo = (ConstantDoubleInfo) cpInfo;
                    constant =new DoubleConstant(doubleInfo.getValue()); // Double
                    i++; // 占两个 slot
                    break;

                case CONSTANT_String:
                    ConstantStringInfo stringInfo = (ConstantStringInfo) cpInfo;
                    constant =new StringConstant(stringInfo.getString()); // String
                    break;

                case CONSTANT_Class:
                    ConstantClassInfo classInfo = (ConstantClassInfo) cpInfo;
                    constant = ClassRef.newClassRef(runtimeConstantPool, classInfo);
                    break;

                case CONSTANT_Fieldref:
                    ConstantFieldrefInfo fieldrefInfo = (ConstantFieldrefInfo) cpInfo;
                    constant = FieldRef.newFieldRef(runtimeConstantPool, fieldrefInfo);
                    break;

                case CONSTANT_Methodref:
                    ConstantMethodrefInfo methodrefInfo = (ConstantMethodrefInfo) cpInfo;
                    constant = MethodRef.newMethodRef(runtimeConstantPool, methodrefInfo);
                    break;

                case CONSTANT_InterfaceMethodref:
                    ConstantInterfaceMethodrefInfo interfacemethodrefInfo = (ConstantInterfaceMethodrefInfo) cpInfo;
                    constant = InterfaceMethodRef.newInterfaceMethodRef(runtimeConstantPool, interfacemethodrefInfo);
                    break;

                default:
                    System.err.println("Unsupported constant type: " + tag + " at index " + i);
                    break;
            }

            if (constant != null) {
                consts[i] = constant;
            }
        }

        return runtimeConstantPool;
    }

    // endregion

    // region Getter & Setter

    public InstanceKlass getInstanceKlass() {
        return instanceKlass;
    }

    public void setInstanceKlass(InstanceKlass instanceKlass) {
        this.instanceKlass = instanceKlass;
    }

    public Constant[] getConsts() {
        return consts;
    }

    public void setConsts(Constant[] consts) {
        this.consts = consts;
    }

    // endregion

    // region 核心方法

    /**
     * 获取指定索引处的常量
     */
    public Constant getConstant(int index) {
        if (index < 0 || index >= consts.length) {
            throw new RuntimeException("Invalid constant pool index: " + index);
        }
        Constant c = consts[index];
        if (c == null) {
            throw new RuntimeException("No constant at index " + index);
        }
        return c;
    }

    public int getSize() {
        return consts.length;
    }

    // endregion
}
